package com.miyu.book.utils.bookUtils;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.miyu.book.utils.ehcache.EhcacheUtil;
import com.miyu.book.utils.redis.redisUtils.util.RedisValUtil;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Request;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.processor.PageProcessor;
import us.codecraft.webmagic.selector.Selectable;

import java.util.List;
import java.util.Map;

/**
 *  统一处理规则解析
 *  每次解析的结果使用ehcache 或redis缓存
 *  key值生成需要调用方传递
 *  返回数据使用JSONObject 后key值根据规则名称取对应值即可
 *  其中取值分 列表取值 以及单个取值，类表中单据取值
 *
 *  解析后数据加入到缓存中 再缓存中处理书籍
 *  数据周期 查询时执行当前规则查询时会先删除当前规则下的缓存数据 再把查询的数据缓存到当前规则下
 *
 *  有章节链接进入明细数据是暂时只删除规则数据
 *
 *
 */
public class RuleJXData implements PageProcessor {

    @Autowired
    private RedisValUtil redisValUtil;
    private JSONObject rs;
    private static String  regex = "\\(([^}]*)\\)";//匹配小括号

    //爬虫配置信息设置
    private Site site = new Site()
            .setCharset("utf-8")    //设置编码
            .setSleepTime(1)        //设置抓取间隔
            .setTimeOut(10000)         //设置超时时间
            .setRetrySleepTime(300)      //设置重试时间
            .setRetryTimes(3);       //设置重试次数
    @Override
    public Site getSite() {
        return this.site;
    }

    public static JSONObject RuleJXDataPage (JSONObject jo){
        Request request = new Request();
        request.setUrl(jo.getString("url"));
        request.putExtra("bookRule",jo.getJSONObject("ruleSet"));//对应解析不同的规则
        request.putExtra("cond",jo.getJSONObject("cond"));//key 以及解析顺序
        request.putExtra("param",jo.getJSONObject("param"));//附加参数传入

        Spider.create(new RuleJXData()).addRequest(request)
                .addPipeline( new saveCacheData())
                .thread(50)
                .run();
        return  null;
    }

    @SneakyThrows
    @Override
    public void process(Page page) {
        Request request = new Request();
        JSONObject cond = page.getRequest().getExtra("cond");//key 以及解析顺序
        JSONObject param = page.getRequest().getExtra("param"); //附加参数传入
        String ruleId = param.getString("ruleId"); // 规则主键 每个必须添加 所有数据根据此携带
        JSONObject bookRule = page.getRequest().getExtra("bookRule");//解析规则 根据不同的key获取不同的规则
        String key = cond.getString("key");
        JSONObject vess = new JSONObject();//当前页面容器
        String url = page.getRequest().getUrl();//当前url连接
        List<String> num = (List<String>) cond.get("num");
        if (num.get(0).equals("bookType")){
            num.remove(0);

        }else if (num.get(0).equals("bookSearch")){
            //搜索列表
            //解析列表
            JSONObject bookSearch = bookRule.getJSONObject("bookSearch");
            String bookList = bookSearch.getString("bookList");
            List<Selectable> list = JXPageUtils.JXPageRuleByPage(page,bookList);
            //之后在解析每列值
            JSONArray ja = new JSONArray();
            for(int i=0;i<list.size();i++){
                //当前页
                JSONObject jo = new JSONObject();
                Selectable stable = list.get(i);
                JSONObject showTitle = bookSearch.getJSONObject("showTitle");
                for (Map.Entry entry : showTitle.entrySet()) {
                    String v = entry.getValue().toString();
                    if(v.trim().length()>0){
                        if(v.indexOf("#")>0){
                            //#做数据分割可做动态查询数据 以及取值数据扩展
                            jo.put(entry.getKey().toString(),JXPageUtils.JXPageRuleByTable(stable,v.substring(0,v.indexOf("#"))));
                        }else {
                            jo.put(entry.getKey().toString(),JXPageUtils.JXPageRuleByTable(stable,v));
                        }
                    }
                }
                jo.put("ruleId",ruleId);
                jo.put("sourceName",cond.getString("keyName"));//规则来源名称
                ja.add(jo);
            }
            if(StringUtils.isNotBlank(bookSearch.getString("pageDown"))){
                //下一页 散养页面
                //jo.put("pageDown",JXPageUtils.JXPageRuleByTable(stable,bookSearch.getString("pageDown")));
            }else{
                //如果有下一页时还是当前规则//如果没有下一页时 移除当前规则顺序
                num.remove(0);
            }
            vess.put("bookSearch",ja);
            page.putField("bookSearch",vess);
            page.putField("type","bookSearch");
            page.putField("key",key);
        }else if(num.get(0).equals("bookChapterList")){
            //明细页面+章节列表
            /**
             * 两种情况
             * 1.一种是详情和章节在一页
             * 2.详情和和章节不再一页情况 详情页按钮或链接跳转进入章节 取章节信息
             */
            JSONObject bdf = new JSONObject();
            //根据当前连接生成bookId 组合成json 加入到缓存中
            JSONObject bif = new JSONObject();
            //书籍主键
            String bookId= BookCommutils.MD5(page.getUrl().toString());

            JSONObject bcl = bookRule.getJSONObject("bookChapterList");//章节明细规则
            JSONObject bookInfo = bcl.getJSONObject("bookInfo");//书籍明细信息
            bif.put("bookId",bookId);//书籍Id
            bif.put("ruleId",ruleId);//规则Id
            bif.put("bookUrl",page.getUrl().toString());//
            for (Map.Entry entry : bookInfo.entrySet()) {
                String v = entry.getValue().toString();
                if(v.trim().length()>0){
                    bif.put(entry.getKey().toString(),JXPageUtils.JXPageRuleByCheckRule(page,v));
                    }
                }
             String bookChapterList = bcl.getString("bookChapterList");
            JSONObject binfo= new JSONObject();
            binfo.put("bookInfo",bif);
            bdf.put(bookId,binfo);
            vess.put(key,bdf);
            //# 说明 明细页面和章节页面不再同一个页面是 需要根据明细页面跳转到章节详情页面 解析章节
            if(bookChapterList.indexOf("#")>0){
                num.remove(0);
                String [] st = bookChapterList.split("#");
                String chapterUrl = st[0];//章节详情连接
                String nextUrl = JXPageUtils.JXPageRuleByCheckRule(page,chapterUrl);//下一个要进行的连接
                page.getRequest().setUrl(nextUrl);
                num.add(0,"chapterList");
                page.getRequest().putExtra("bookInfo",bdf);
                page.getRequest().putExtra("bookId",bookId);
                cond.put("num",num);
                page.getRequest().putExtra("cond",cond);
                page.addTargetRequest(page.getRequest());
                page.setSkip(true);
            }else{
                //明细和章节在同一页面

            }
            //加入到缓存中
            JSONObject bs = (JSONObject) EhcacheUtil.getInstance().get("bookEhcache",key);
            //num.remove(0);
        }else if(num.get(0).equals("chapterContext")){
            //章节阅读
            JSONObject br = bookRule.getJSONObject("chapterContext");
          //  JSONObject bif = new JSONObject();
            //从搜索页面进入是未必有生成 书的ID 未生成ID 是应该有书的连接 根据连接生成ID 确定是哪本书的Id
            String bookId ;
            if(param.containsKey("chapterId"))
                bookId = param.getString("bookId");
            else
                bookId = BookCommutils.MD5(param.getString("bookUrl"));
            //根据连接生成章节id 避免查询或明细跳转 找不到章节ID
            String  chapterId = param.getString("chapterId");

            for (Map.Entry entry : param.entrySet()) {
                vess.put(entry.getKey().toString(),entry.getValue());
            }

            for (Map.Entry entry : br.entrySet()) {
                String v = entry.getValue().toString();
                if(v.trim().length()>0){
                    vess.put(entry.getKey().toString(),JXPageUtils.JXPageRuleByCheckRule(page,v));
                }
            }
            page.putField("chapterContext",vess);
            page.putField("type",param.getString("type"));
            page.putField("key",key);

            //获取数据更新到缓存中区
            //文本列表
            num.remove(0);

        }else if(num.get(0).equals("chapterList")){
            //此方法处理章节列表和明细不再同一页面
            JSONObject bookInfo = page.getRequest().getExtra("bookInfo");
            //文本列表
            JSONObject bif = page.getRequest().getExtra("bookInfo");//书籍明细数据
            JSONObject bcl = bookRule.getJSONObject("bookChapterList");//章节明细规则
            String bookChapterList = bcl.getString("bookChapterList");
            String [] st = bookChapterList.split("#");
            JSONObject chapterInfo = bcl.getJSONObject("chapterInfo");//章节取值规则
            List<Selectable> list = JXPageUtils.JXPageRuleByPage(page,st[1]);//当前列表规则
            String bookId = page.getRequest().getExtra("bookId");//当前书籍主键 唯一标识
            JSONArray ja = new JSONArray(); //返回JSONArray数据
           JSONObject chlist = new JSONObject();//章节 json返回
            for(int i=0;i<list.size();i++){
                JSONObject ch = new JSONObject();
               // String chapterName = chapterInfo.getString("chapterName");
                String chapterUrl = JXPageUtils.JXPageRuleByTable(list.get(i),chapterInfo.getString("chapterUrl"));
                String chapterId = BookCommutils.MD5(chapterUrl);
                ch.put("chapterUrl",chapterUrl);
                ch.put("chapterName",JXPageUtils.JXPageRuleByTable(list.get(i),chapterInfo.getString("chapterName")));
                ch.put("bookId",bookId);
                ch.put("chapterId",chapterId);
                ch.put("ruleId",ruleId);
                ch.put("num",i+1);
                if(i==list.size()-1)
                    ch.put("last","1");
                else
                    ch.put("last","0");
                chlist.put(chapterId,ch);
               // ja.add(ch);
            }
           // bookInfo.getJSONObject(bookId).put("chapterInfo",ja);
            vess.put("bookInfo",bookInfo.getJSONObject(bookId).getJSONObject("bookInfo"));
            vess.put("chapterInfo",chlist);
            //解析数据加入到缓存一共后续处理
            page.putField("bookChapterList",vess);
            page.putField("type",param.getString("type"));
            page.putField("key",key);
            num.remove(0);

        }else if(num.get(0).equals("downFile")){
            //文件下载

            JSONObject br = bookRule.getJSONObject("chapterContext");
            //String context = JXPageUtils.JXPageRuleByCheckRule(page,br.getString("chapterContext"));
            String context = JXPageUtils.JXPageRuleByCheckRule(page,br.getString("chapterContext"));
            //param.put("context",context);
            vess.put("num",param.getInteger("num"));
            vess.put("context",context);
            vess.put("chapterName",param.getString("chapterName"));

            page.putField("downFile",vess);
            page.putField("type","downFile");
            page.putField("key",key);

        }
    }
}

